/*************************************************************************
	Sound Buffer

*************************************************************************/

using UnityEngine;
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;

[Serializable]
public class UTVPSliLabel {
	public int position = 0;
	public string name = "";
}

[Serializable]
public class UTVPSliLink {
	public enum LINK_CONDITION {
		no,
		eq,
		ne,
		gt,
		ge,
		lt,
		le
	}
	public int from = 0;
	public int to = 0;
	public bool smooth = false;
	public LINK_CONDITION condition = LINK_CONDITION.no;
	public int condVar = 0; // [0, 15]
	public int refValue = 0;
	
	public bool ChechCond(int[] flags)
	{
		switch(condition)
		{
		case LINK_CONDITION.no:
			return true;
		case LINK_CONDITION.eq:
			return flags[condVar] == refValue;
		case LINK_CONDITION.ne:
			return flags[condVar] != refValue;
		case LINK_CONDITION.gt:
			return flags[condVar] > refValue;
		case LINK_CONDITION.ge:
			return flags[condVar] >= refValue;
		case LINK_CONDITION.lt:
			return flags[condVar] < refValue;
		case LINK_CONDITION.le:
			return flags[condVar] <= refValue;
		default:
			return true;
		}
	}
}

[Serializable]
public class UTVPSoundBuffer_SaveData
{
	public UTVPSoundBuffer_SaveData() {}
		
	public string audio = null;
	public bool loop = false;
	public int volume = 100;
	public int pan = 0;
	public bool isPlaying = false;
	public bool paused = false;
	public int samplePosition = 0;
	public int[] flags;
}

[RequireComponent(typeof(AudioSource))]
public class UTVPSoundBuffer : MonoBehaviour {
	
	protected UTVPSystem mSystem = null;
	public UTVPSystem System { get { return mSystem; } }
	protected AudioSource mBuf;
	public AudioSource Buf { get { return mBuf; } }
	protected int mLastSamplePosition = 0;
	
	private int m_FadeBeginVolume = 0;
	private int m_FadeEndVolume = 0;
	private float m_FadeBeginTime = 0;
	private float m_FadeTimeLength = 0;
	
	public static UTVPSoundBuffer CreateSoundBuffer(UTVPSystem system, string name) {
		GameObject obj = new GameObject(name);
		obj.transform.parent = system.transform;
		UTVPSoundBuffer soundBuffer = obj.AddComponent<UTVPSoundBuffer>();
		soundBuffer.mSystem = system;
		
		return soundBuffer;
	}
	
	public void open(AudioClip ukagAudio)
	{
		mBuf.clip = ukagAudio;
		labels = new UTVPSliLabel[0];
		links = new UTVPSliLink[0];
	}
	
	public void open(UTVPAudio ukagAudio)
	{
		mBuf.clip = ukagAudio.Clip;
		labels = new UTVPSliLabel[0];
		links = new UTVPSliLink[0];
		if (ukagAudio.Sli != null)
		{
			labels = ukagAudio.Labels;
			links = ukagAudio.Links;
		}
	}
	
	public void play() // ( メディアを再生する )
	{
		if (mBuf.clip != null)
			mBuf.Play();
		else
			Debug.LogError("SoundBuffer " + name + " did not load the audio clip");
	}
	
	public void play(AudioClip ukagAudio)
	{
		open(ukagAudio);
		play();
	}
	
	public void play(UTVPAudio ukagAudio)
	{
		open(ukagAudio);
		play();
	}
	
	public void fade(int to, int time, int delay) // ( フェードを開始する )
	{
		m_FadeBeginVolume = volume;
		m_FadeEndVolume = to;
		m_FadeBeginTime = Time.time + delay / 1000.0f;
		m_FadeTimeLength = time / 1000.0f;
	}
	
	public void stop() //  ( メディアを停止する )
	{
		mBuf.Stop();
	}
	
	public void stopFade() // ( フェードを停止する )
	{
		m_FadeTimeLength = 0;
		OnFadeComplete(true);
	}
	
	protected virtual void OnFadeComplete(bool skipped)
	{
	}
	
	public static void loadSli(TextAsset sliFile, ref UTVPSliLabel[] labels, ref UTVPSliLink[] links)
	{
		Stream s = new MemoryStream(sliFile.bytes);
		StreamReader sr = new StreamReader(s);
		int paramValueStart, paramValueEnd;
		UTVPSliLabel label = null;
		UTVPSliLink link = null;
		List<UTVPSliLabel> labelList = new List<UTVPSliLabel>();
		List<UTVPSliLink> linkList = new List<UTVPSliLink>();
		string line = sr.ReadLine();
		line = sr.ReadLine();
		line = sr.ReadLine();
		line = sr.ReadLine();
		while (line != null && line != "")
		{
			if (line[1] == 'i') // Link
			{
				link = new UTVPSliLink();
				
				paramValueStart = line.IndexOf('=');
				paramValueEnd = line.IndexOf(';', paramValueStart);
				link.from = int.Parse(line.Substring(paramValueStart + 1, paramValueEnd - paramValueStart - 1));

				paramValueStart = line.IndexOf('=', paramValueEnd);
				paramValueEnd = line.IndexOf(';', paramValueStart);
				link.to = int.Parse(line.Substring(paramValueStart + 1, paramValueEnd - paramValueStart - 1));

				paramValueStart = line.IndexOf('=', paramValueEnd);
				paramValueEnd = line.IndexOf(';', paramValueStart);
				link.smooth = line.Substring(paramValueStart + 1, paramValueEnd - paramValueStart - 1) == "True";

				paramValueStart = line.IndexOf('=', paramValueEnd);
				paramValueEnd = line.IndexOf(';', paramValueStart);
				link.condition = (UTVPSliLink.LINK_CONDITION)Enum.Parse(typeof(UTVPSliLink.LINK_CONDITION), line.Substring(paramValueStart + 1, paramValueEnd - paramValueStart - 1));

				paramValueStart = line.IndexOf('=', paramValueEnd);
				paramValueEnd = line.IndexOf(';', paramValueStart);
				link.refValue = int.Parse(line.Substring(paramValueStart + 1, paramValueEnd - paramValueStart - 1));

				paramValueStart = line.IndexOf('=', paramValueEnd);
				paramValueEnd = line.IndexOf(';', paramValueStart);
				link.condVar = int.Parse(line.Substring(paramValueStart + 1, paramValueEnd - paramValueStart - 1));


				linkList.Add(link);
			}
			else if (line[1] == 'a') // Label
			{
				label = new UTVPSliLabel();
				
				paramValueStart = line.IndexOf('=');
				paramValueEnd = line.IndexOf(';', paramValueStart);
				label.position = int.Parse(line.Substring(paramValueStart + 1, paramValueEnd - paramValueStart - 1));

				paramValueStart = line.IndexOf('\'', paramValueEnd);
				paramValueEnd = line.IndexOf('\'', paramValueStart + 1);
				label.name = line.Substring(paramValueStart + 1, paramValueEnd - paramValueStart - 1);
				
				labelList.Add(label);
			}
				
			line = sr.ReadLine();
		}
		
		labels = labelList.ToArray();
		links = linkList.ToArray();
	}

	public enum SOUNDBUFFER_FOCUS_MODE {
		sgfmNeverMute,
		sgfmMuteOnMinimize,
		sgfmMuteOnDeactivate
	}
	// ( フォーカスモード )
	public static SOUNDBUFFER_FOCUS_MODE globalFocusMode = SOUNDBUFFER_FOCUS_MODE.sgfmNeverMute;
	
	// ( サンプリング周波数 )
	public int frequency { get { if(mBuf.clip != null) return mBuf.clip.frequency; else return 0; } }
	// ( チャンネル数 )
	public int channels { get { if(mBuf.clip != null) return mBuf.clip.channels; else return 0; } }
	
	/// <summary>
	/// Gets or sets a value indicating whether this <see cref="UTVPSoundBuffer"/> is mute.
	/// </summary>
	/// <value>
	/// <c>true</c> if mute; otherwise, <c>false</c>.
	/// </value>
	public bool Mute { get { return mBuf.mute; } set { mBuf.mute = value; } }

	private int mVolume = 100;
	public int volume
	{
		get { return mVolume;  }
		set { mVolume = value; mBuf.volume = mGlobalVolume * mVolume / 10000.0f; }
	}
	private int mGlobalVolume = 100;
	public int globalVolume
	{
		get { return mGlobalVolume;  }
		set { mGlobalVolume = value; mBuf.volume = mGlobalVolume * mVolume / 10000.0f; }
	}
	
	public bool looping { get { return mBuf.loop; } set { mBuf.loop = value; }}
	
	public int pan { get { return (int)(mBuf.pan * 100); } set { mBuf.pan = value / 100.0f; } }
	
	public bool isPlaying { get { return mBuf.isPlaying; } }
	
	public bool paused
	{
		get { return !mBuf.isPlaying && mBuf.timeSamples > 0; }
		set
		{
			if (mBuf.clip == null)
				return;
			if (value)
				mBuf.Pause();
			else
				mBuf.Play();
		}
	}
	
	public int position { get { return (int)(mBuf.time * 1000); } set { mBuf.time = value / 1000.0f; } }

	public int samplePosition { get { return mBuf.timeSamples; } set { mBuf.timeSamples  = value; } }

	public enum SOUNDBUFFER_STATE {
		unload,
		play,
		stop
	}
	public SOUNDBUFFER_STATE status {
		get
		{
			if (mBuf.clip == null)
				return SOUNDBUFFER_STATE.unload;
			if (!mBuf.isPlaying && mBuf.timeSamples == 0)
				return SOUNDBUFFER_STATE.stop;
			else
				return SOUNDBUFFER_STATE.play;
		}
	}

	public int totalTime { get { if (mBuf.clip == null) return 0; else return (int)(mBuf.clip.length * 1000); } }
	
	public int[] flags = null; // 这个不是从sli里读取的,而是在执行过程中按需要设置的条件参数

	public UTVPSliLabel[] labels = null;
	
	public UTVPSliLink[] links = null;

	//onFadeCompleted ( フェードが終了した )
	//onLabel ( ラベルを通過した )
	//onStatusChanged ( ステータスが変更された )
	
	public static T CreateSoundBuffer<T>(UTVPSystem system, string name, int gameObjLayer) where T : UTVPSoundBuffer
	{
		GameObject obj = new GameObject(name);
		obj.transform.parent = system.transform;
		T soundBuffer = obj.AddComponent<T>();
		soundBuffer.mSystem = system;
		obj.layer = gameObjLayer;
		
		return soundBuffer;
	}

	// Use this for initialization
	protected virtual void  Awake ()
	{
		mBuf = GetComponent<AudioSource>();
		flags = new int[15];
	}
	
	protected virtual void  Start()
	{
	}
	
	// Update is called once per frame
	protected virtual void  Update ()
	{
		if (links != null)
		{
			for (int i=0; i<links.Length; i++)
			{
				if(mLastSamplePosition <= links[i].from && links[i].from <= samplePosition && links[i].ChechCond(flags))
					samplePosition = links[i].to;
			}
		}
		mLastSamplePosition = samplePosition;
		
		if (m_FadeTimeLength > 0)
		{
			if (m_FadeBeginTime <= Time.time && Time.time <= m_FadeBeginTime + m_FadeTimeLength)
			{
				float currVolume = Mathf.Lerp(m_FadeBeginVolume, m_FadeEndVolume, (Time.time - m_FadeBeginTime) / m_FadeTimeLength);
				mVolume = (int)currVolume;
				mBuf.volume = mGlobalVolume * currVolume / 10000.0f;
			}
			else if (Time.time > m_FadeBeginTime + m_FadeTimeLength)
			{
				mVolume = m_FadeEndVolume;
				mBuf.volume = mGlobalVolume * mVolume / 10000.0f;
				m_FadeTimeLength = 0;
				OnFadeComplete(false);
			}
		}
	}
	
	protected virtual UTVPSoundBuffer_SaveData CreateSaveDataBuff()
	{
		return new UTVPSoundBuffer_SaveData();
	}
	
	protected virtual void GetSelfData(UTVPSoundBuffer_SaveData dataBuff)
	{
		dataBuff.audio = mBuf.clip != null ? mBuf.clip.name : null;
		dataBuff.loop = looping;
		dataBuff.volume = mVolume;
		dataBuff.pan = pan;
		dataBuff.isPlaying = mBuf.isPlaying;
		dataBuff.paused = paused;
		dataBuff.samplePosition = samplePosition;
		dataBuff.flags = flags;
	}
	
	public UTVPSoundBuffer_SaveData GetData()
	{
		UTVPSoundBuffer_SaveData dataBuff = CreateSaveDataBuff();
		GetSelfData(dataBuff);
		
		return dataBuff;
	}
	
	protected virtual void SetSelfData(UTVPSoundBuffer_SaveData dataBuff)
	{
		UTVPAudio ukagAudio = mSystem.Storages.GetAudio(dataBuff.audio);
		if (ukagAudio != null)
			open(ukagAudio);
		else
			stop();
		looping = dataBuff.loop;
		volume = dataBuff.volume;
		pan = dataBuff.pan;
		paused = dataBuff.paused;
		flags = dataBuff.flags;
	}
	
	public void SetData(UTVPSoundBuffer_SaveData dataBuff)
	{
		SetSelfData(dataBuff);
		
		if (dataBuff.isPlaying)
		{
			if(!paused)
			{
				play();
			}
			else
			{
				samplePosition = dataBuff.samplePosition;
				mBuf.Pause();
			}
		}
		else
			mBuf.Stop();
	}
}
